package com.hh.controller;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.Dict;
import com.hh.annotation.AuthCheck;
import com.hh.common.BaseResponse;
import com.hh.common.ErrorCode;
import com.hh.common.ResultUtils;
import com.hh.constant.UserConstant;
import com.hh.entity.domain.User;
import com.hh.exception.BusinessException;
import com.hh.exception.ThrowUtils;
import com.hh.manager.MarkdownService;
import com.hh.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.minio.MinioFileStorageService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

/**
 * 文件控制器，提供文件上传、下载等功能
 *
 * @author hanhui
 */
@Slf4j
@RestController
@RequestMapping("/files")
public class FileController {
    /**
     * 用户服务接口
     */
    @Resource
    private UserService userService;
    @Resource
    private MarkdownService markdownService;
    /**
     * Minio文件存储服务
     */
    MinioFileStorageService minioFileStorageService;

    /**
     * 构造函数，注入Minio文件存储服务
     *
     * @param minioFileStorageService Minio文件存储服务
     */
    @Autowired
    public FileController(MinioFileStorageService minioFileStorageService) {
        this.minioFileStorageService = minioFileStorageService;
    }

    /**
     * 上传文件接口
     *
     * @param file 上传的文件
     * @return 返回文件访问URL
     * @throws BusinessException 当文件为空或系统错误时抛出
     */
    @PostMapping("/upload")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public BaseResponse<String> uploadFile(@RequestParam("file") MultipartFile file) {
        if (file.isEmpty()) {
            throw new BusinessException(ErrorCode.DATA_NULL_ERROR);
        }

        try {
            String filePath = System.getProperty("user.dir") + "/files/";
            if (!FileUtil.isDirectory(filePath)) {
                FileUtil.mkdir(filePath);
            }
            byte[] bytes = file.getBytes();
            // 生成随机文件名
            String originalFileName = file.getOriginalFilename();
            String fileName = System.currentTimeMillis() + "-" + originalFileName;
            FileUtil.writeBytes(bytes, filePath + fileName);

            // 返回文件URL
            String downFileUrl = "http://localhost:8080/api/files/download/" + fileName;
            return ResultUtils.success(downFileUrl);

        } catch (IOException e) {
            throw new BusinessException(ErrorCode.SYSTEM_ERROR);
        }
    }

    /**
     * 下载文件接口
     *
     * @param fileName 文件名
     * @param response HTTP响应对象
     * @throws Exception 当文件不存在或发生IO错误时抛出
     */
    @GetMapping("/download/{fileName}")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public void downloadFile(@PathVariable String fileName, HttpServletResponse response) throws Exception {
        String filePath = System.getProperty("user.dir") + "/files/";
        String realPath = filePath + fileName;
        if (FileUtil.exist(realPath)) {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
            byte[] bytes = FileUtil.readBytes(realPath);
            ServletOutputStream os = response.getOutputStream();
            os.write(bytes);
            os.flush();
            os.close();
        } else {
            throw new BusinessException(ErrorCode.FILE_NOT_FOUND);
        }
    }

    /**
     * 富文本编辑器文件上传接口
     *
     * @param file 上传的文件
     * @return 返回上传结果，包含文件访问URL
     * @throws RuntimeException 当文件上传失败时抛出
     */
    @PostMapping("/wang/upload")
    @AuthCheck(mustRole = UserConstant.ADMIN_ROLE)
    public Map<String, Object> upload(MultipartFile file) {
        String flag = System.currentTimeMillis() + "";
        String fileName = file.getOriginalFilename();
        String filePath = System.getProperty("user.dir") + "/files/";
        try {
            FileUtil.writeBytes(file.getBytes(), filePath + flag + "-" + fileName);
            Thread.sleep(1000);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        String http = "http://localhost:8080/api" + "/files/download/";
        Map<String, Object> resMap = new HashMap<>();
        resMap.put("erroe", 0);
        resMap.put("data", CollUtil.newArrayList(
                Dict.create().set("url", http + flag + "-" + fileName)
                        .set("alt", "")
                        .set("href", "")
        ));
        return resMap;
    }

    /**
     * 博客文章图片上传接口
     *
     * @param file    上传的文件
     * @param request HTTP请求对象
     * @return 返回文件访问URL
     */
    @PostMapping("/blog/upload")
    public BaseResponse<String> mdFile(@RequestParam("file") MultipartFile file, HttpServletRequest request) {
        User loginUser = userService.getLoginUser(request);
        String path = loginUser.getId() + "";
        validPicture(file);
        String uploadFile = minioFileStorageService.uploadFile(file, path, "test");
        String fileUrl = minioFileStorageService.getFileUrl(uploadFile);

        log.info("uploadFile: {}, fileUrl: {}", uploadFile, fileUrl);
        return ResultUtils.success(fileUrl);
    }

    /**
     * 校验图片文件
     *
     * @param multipartFile 上传的文件
     * @throws BusinessException 当文件为空、大小超过限制或文件类型错误时抛出
     */
    private void validPicture(MultipartFile multipartFile) {
        ThrowUtils.throwIf(multipartFile == null, ErrorCode.PARAMS_ERROR, "文件不能为空");
        // 1. 校验文件大小
        long fileSize = multipartFile.getSize();
        final long ONE_M = 1024 * 1024L;
        ThrowUtils.throwIf(fileSize > 2 * ONE_M, ErrorCode.PARAMS_ERROR, "文件大小不能超过 2M");
        // 2. 校验文件后缀
        String fileSuffix = FileUtil.getSuffix(multipartFile.getOriginalFilename());
        // 允许上传的文件后缀
        final List<String> ALLOW_FORMAT_LIST = Arrays.asList("jpeg", "jpg", "png", "webp");
        ThrowUtils.throwIf(!ALLOW_FORMAT_LIST.contains(fileSuffix), ErrorCode.PARAMS_ERROR, "文件类型错误");
    }

    @PostMapping("/upload/md")
    public BaseResponse<List<String>> uploadMarkdownFiles(@RequestParam("files") MultipartFile[] files, HttpServletRequest request) {

        if (files == null || files.length == 0) {
            throw new BusinessException(ErrorCode.PARAMS_NULL);
        }

        CompletableFuture<List<String>> future = markdownService.processMarkdownFiles(files, request);
        List<String> results = future.join();
        return ResultUtils.success(results);
    }

}